package com.cxm.qyyz.utils;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.FloatRange;
import androidx.core.content.ContextCompat;

import com.cxm.qyyz.app.App;
import com.cxm.qyyz.core.http.DefaultObserver;
import com.cxm.qyyz.utils.flow.LogUtils;

import junit.framework.Assert;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.schedulers.Schedulers;

public class Util {

    private static final String TAG = "SDK_Sample.Util";
    private static long lastClickTime;

    public static byte[] bmpToByteArray(final Bitmap bmp, final boolean needRecycle) {
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        bmp.compress(CompressFormat.PNG, 100, output);
        if (needRecycle) {
            bmp.recycle();
        }

        byte[] result = output.toByteArray();
        try {
            output.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return result;
    }

    /**
     * 判断是否为空
     */
    public static boolean isEmpty(Object obj) {
        if (obj == null) {
            return true;
        }
        if (obj instanceof CharSequence){
            String str = obj.toString().trim();
            return str.length() == 0 || TextUtils.equals(str,"null");
        }
        if (obj.getClass().isArray() && Array.getLength(obj) == 0) {
            return true;
        }
        if (obj instanceof Collection && ((Collection) obj).isEmpty()) {
            return true;
        }
        if (obj instanceof Map && ((Map) obj).isEmpty()) {
            return true;
        }
        if (obj instanceof SparseArray && ((SparseArray) obj).size() == 0) {
            return true;
        }
        return false;
    }

    public static byte[] getHtmlByteArray(final String url) {
        URL htmlUrl = null;
        InputStream inStream = null;
        try {
            htmlUrl = new URL(url);
            URLConnection connection = htmlUrl.openConnection();
            HttpURLConnection httpConnection = (HttpURLConnection) connection;
            int responseCode = httpConnection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                inStream = httpConnection.getInputStream();
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        byte[] data = inputStreamToByte(inStream);

        return data;
    }

    public static byte[] inputStreamToByte(InputStream is) {
        try {
            ByteArrayOutputStream bytestream = new ByteArrayOutputStream();
            int ch;
            while ((ch = is.read()) != -1) {
                bytestream.write(ch);
            }
            byte imgdata[] = bytestream.toByteArray();
            bytestream.close();
            return imgdata;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    public static byte[] readFromFile(String fileName, int offset, int len) {
        if (fileName == null) {
            return null;
        }

        File file = new File(fileName);
        if (!file.exists()) {
            Log.i(TAG, "readFromFile: file not found");
            return null;
        }

        if (len == -1) {
            len = (int) file.length();
        }

        Log.d(TAG, "readFromFile : offset = " + offset + " len = " + len + " offset + len = " + (offset + len));

        if (offset < 0) {
            Log.e(TAG, "readFromFile invalid offset:" + offset);
            return null;
        }
        if (len <= 0) {
            Log.e(TAG, "readFromFile invalid len:" + len);
            return null;
        }
        if (offset + len > (int) file.length()) {
            Log.e(TAG, "readFromFile invalid file len:" + file.length());
            return null;
        }

        byte[] b = null;
        try {
            RandomAccessFile in = new RandomAccessFile(fileName, "r");
            b = new byte[len]; // 创建合适文件大小的数组
            in.seek(offset);
            in.readFully(b);
            in.close();

        } catch (Exception e) {
            Log.e(TAG, "readFromFile : errMsg = " + e.getMessage());
            e.printStackTrace();
        }
        return b;
    }

    private static final int MAX_DECODE_PICTURE_SIZE = 1920 * 1440;

    public static Bitmap extractThumbNail(final String path, final int height, final int width, final boolean crop) {
        Assert.assertTrue(path != null && !path.equals("") && height > 0 && width > 0);

        BitmapFactory.Options options = new BitmapFactory.Options();

        try {
            options.inJustDecodeBounds = true;
            Bitmap tmp = BitmapFactory.decodeFile(path, options);
            if (tmp != null) {
                tmp.recycle();
                tmp = null;
            }

            Log.d(TAG, "extractThumbNail: round=" + width + "x" + height + ", crop=" + crop);
            final double beY = options.outHeight * 1.0 / height;
            final double beX = options.outWidth * 1.0 / width;
            Log.d(TAG, "extractThumbNail: extract beX = " + beX + ", beY = " + beY);
            options.inSampleSize = (int) (crop ? (beY > beX ? beX : beY) : (beY < beX ? beX : beY));
            if (options.inSampleSize <= 1) {
                options.inSampleSize = 1;
            }

            // NOTE: out of memory error
            while (options.outHeight * options.outWidth / options.inSampleSize > MAX_DECODE_PICTURE_SIZE) {
                options.inSampleSize++;
            }

            int newHeight = height;
            int newWidth = width;
            if (crop) {
                if (beY > beX) {
                    newHeight = (int) (newWidth * 1.0 * options.outHeight / options.outWidth);
                } else {
                    newWidth = (int) (newHeight * 1.0 * options.outWidth / options.outHeight);
                }
            } else {
                if (beY < beX) {
                    newHeight = (int) (newWidth * 1.0 * options.outHeight / options.outWidth);
                } else {
                    newWidth = (int) (newHeight * 1.0 * options.outWidth / options.outHeight);
                }
            }

            options.inJustDecodeBounds = false;

            Log.i(TAG, "bitmap required size=" + newWidth + "x" + newHeight + ", orig=" + options.outWidth + "x" + options.outHeight + ", sample=" + options.inSampleSize);
            Bitmap bm = BitmapFactory.decodeFile(path, options);
            if (bm == null) {
                Log.e(TAG, "bitmap decode failed");
                return null;
            }

            Log.i(TAG, "bitmap decoded size=" + bm.getWidth() + "x" + bm.getHeight());
            final Bitmap scale = Bitmap.createScaledBitmap(bm, newWidth, newHeight, true);
            if (scale != null) {
                bm.recycle();
                bm = scale;
            }

            if (crop) {
                final Bitmap cropped = Bitmap.createBitmap(bm, (bm.getWidth() - width) >> 1, (bm.getHeight() - height) >> 1, width, height);
                if (cropped == null) {
                    return bm;
                }

                bm.recycle();
                bm = cropped;
                Log.i(TAG, "bitmap croped size=" + bm.getWidth() + "x" + bm.getHeight());
            }
            return bm;

        } catch (final OutOfMemoryError e) {
            Log.e(TAG, "decode bitmap failed: " + e.getMessage());
            options = null;
        }

        return null;
    }

    public static int parseInt(final String string, final int def) {
        try {
            return (string == null || string.length() <= 0) ? def : Integer.parseInt(string);

        } catch (Exception e) {
        }
        return def;
    }


    /**
     * @param clazz 参数实体类
     * @return String
     * @Title: getPostParams
     * @Description: 将实体类clazz的属性转换为url参数
     */
    public static String getPostParams(Object clazz) {
        // 遍历属性类、属性值
        Field[] fields = clazz.getClass().getDeclaredFields();

        StringBuilder requestURL = new StringBuilder();
        try {
            boolean flag = true;
            String property, value;
            for (int i = 0; i < fields.length; i++) {
                Field field = fields[i];
                // 允许访问私有变量
                field.setAccessible(true);

                // 属性名
                property = field.getName();
                // 属性值
                value = field.get(clazz).toString();

                String params = property + "=" + value;
                if (flag) {
                    requestURL.append(params);
                    flag = false;
                } else {
                    requestURL.append("&" + params);
                }
            }
        } catch (Exception e) {
        }
        return requestURL.toString();
    }

    /**
     * @param clazz 参数实体类
     * @return String
     * @Title: getPostParams
     * @Description: 将实体类clazz的属性转换为url参数
     */
//    public static String getPostParams(String clazz) {
//        String json = getJson(clazz);
//        ZSPayEntity zsPay = GsonUtils.fromJson(json, ZSPayEntity.class);
//        return getPostParams(zsPay);
//    }

    public static String getJson(String fileName) {
        //将json数据变成字符串
        StringBuilder stringBuilder = new StringBuilder();
        try {
            //获取assets资源管理器
            AssetManager assetManager = App.getInstance().getAssets();
            //通过管理器打开文件并读取
            BufferedReader bf = new BufferedReader(new InputStreamReader(
                    assetManager.open(fileName)));
            String line;
            while ((line = bf.readLine()) != null) {
                stringBuilder.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return stringBuilder.toString();
    }

    public static Object getWelfareGrowthValue(int a) {
        if (a < 0) return 0;
        Object object;
        if (a > 10000) {
            object = divide(a, 10000);
        } else {
            object = a;
        }
        return object;
    }

    public static String divide(double a, int b) {
        DecimalFormat dF = new DecimalFormat("0.00");
        String s = dF.format((float) a / b);
        if (s.endsWith("0")) {
            return s.substring(0, s.length() - 1) + "万";
        } else {
            return s + "万";
        }
    }

    public static boolean isEmpty(List<?> list) {
        return null == list || list.size() == 0;
    }

    /**
     * 从assets中获取文件内容
     *
     * @param fileName 文件名
     * @return 文件内容
     */
    public static String getDataFromAssets(Context context, String fileName) {
        StringBuilder builder = new StringBuilder();
        try {
            InputStreamReader inputReader = new InputStreamReader(context.getResources().getAssets().open(fileName));
            BufferedReader bufReader = new BufferedReader(inputReader);
            String line;
            while ((line = bufReader.readLine()) != null)
                builder.append(line);
        } catch (Exception e) {
            e.printStackTrace();
            LogUtils.d("getDataFromAssets " + e);
            return null;
        }
        return builder.toString();
    }

    public static double String2Double(String s) {
        if (TextUtils.isEmpty(s)) return 0;
        try {
            return Double.parseDouble(s);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    public static boolean isFastClick(int interval){
        boolean flag = false;
        long currClickTime = System.currentTimeMillis();
        if (Math.abs(currClickTime - lastClickTime) < interval){
            flag = true;
        }else {
            lastClickTime = currClickTime;
        }
        return flag;
    }

    /**
     * 设置activity的饱和度,0为灰度效果
     */
    public static void setSaturation(View view, @FloatRange(from = 0,to = 1) float sat){
        Paint paint = new Paint();
        ColorMatrix cm = new ColorMatrix();
        cm.setSaturation(sat);//0为灰度效果
        paint.setColorFilter(new ColorMatrixColorFilter(cm));
        view.setLayerType(View.LAYER_TYPE_HARDWARE,paint);
    }

    public static boolean isSameOfDay(long time1,long time2){
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
            Date t1 = sdf.parse(sdf.format(time1));
            Date t2 = sdf.parse(sdf.format(time2));
            return Objects.requireNonNull(t1).compareTo(t2) == 0;
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return false;
    }

    public static void copyText(Context context, CharSequence data){
        ClipboardManager cm = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
        if (cm != null) {
            cm.setPrimaryClip(ClipData.newPlainText(data,data));
        }
    }

    public static String pasteText(Context context){
        ClipboardManager cbm = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
        String pasteData = "";
        if (cbm != null) {
            ClipData clipData = cbm.getPrimaryClip();
            if (clipData != null && clipData.getItemCount() > 0) {
                pasteData = clipData.getItemAt(0).coerceToText(context).toString();
            }
        }
        return pasteData;
    }

    public static void clearText(Context context){
        ClipboardManager cm = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
        if (cm != null) {
            ClipData clip = cm.getPrimaryClip();
            if (clip != null && clip.getItemCount() > 0) {
                cm.setPrimaryClip(ClipData.newPlainText(null, ""));
            }
        }
    }

    /**
     * 获取当前时间
     * @param pattern 时间显示格式
     */
    public static String getCurrTime(String pattern){
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat(pattern, Locale.getDefault());
        return sdf.format(date);
    }

    /**
     * 获取当前时间
     */
    public static long getCurrTimeLength(){
        Date date = new Date();
        return date.getTime();
    }

    /**
     * 获取时间,通过时间长度
     */
    public static String getTimeByTimeLen(long time, String pattern){
        Date date = new Date(time);
        SimpleDateFormat sdf = new SimpleDateFormat(pattern, Locale.getDefault());
        String format = sdf.format(date);
        return format;
    }

    /**
     * 获取时间长度,通过时间字符串
     */
    public static long getTimeLenByTimeStr(String time, String pattern) {
        try{
            SimpleDateFormat sdf = new SimpleDateFormat(pattern, Locale.getDefault());
            Date date = sdf.parse(time);
            if (date == null) {
                return 0;
            } else {
                return date.getTime();
            }
        }catch (ParseException e){
            e.printStackTrace();
        }
        return 0;
    }

    /**
     * 倒计时动画
     * @param animView 动画的view,textview或imageview
     * @param count 如果是textview为倒计时的总数,如果是imageview为drawableRes的长度
     * @param imgPrefix 图片名称前缀
     */
    public static void countdownAnim(View animView, int count,String imgPrefix,Animator.AnimatorListener listener){
        int[] drawableRes = new int[count];
        for (int i = drawableRes.length; i >= 0; i--) {
            int drawableId = animView.getResources().getIdentifier(String.format("%s%s", imgPrefix, i), "drawable", animView.getContext().getPackageName());
            if (drawableId != 0){
                drawableRes[i - 1] = drawableId;
            }
        }
        countdownAnim(animView, count, drawableRes,listener);
    }

    /**
     * 倒计时动画
     * @param animView 动画的view,textview或imageview
     * @param count 如果是textview为倒计时的总数,如果是imageview为drawableRes的长度
     * @param drawableRes animView为imageview时有效,可为空
     */
    public static void countdownAnim(View animView, int count, int[] drawableRes, Animator.AnimatorListener listener) {
        int repeatCount = count - 1;//定义重复字数（执行动画1次 + 重复动画4次 = 公共5次）
        List<Animator> animators = new ArrayList<>();
        ObjectAnimator scaleXAnim = ObjectAnimator.ofFloat(animView, View.SCALE_X,0.5f,1f);
        scaleXAnim.setDuration(1000);
        scaleXAnim.setRepeatMode(ValueAnimator.RESTART);
        scaleXAnim.setInterpolator(new LinearInterpolator());
        scaleXAnim.setRepeatCount(repeatCount);
        animators.add(scaleXAnim);

        ObjectAnimator scaleYAnim = ObjectAnimator.ofFloat(animView, View.SCALE_Y,0.5f,1f);
        scaleYAnim.setDuration(1000);
        scaleYAnim.setRepeatMode(ValueAnimator.RESTART);
        scaleYAnim.setInterpolator(new LinearInterpolator());
        scaleYAnim.setRepeatCount(repeatCount);
        animators.add(scaleYAnim);

        ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(animView, View.ALPHA,1f,0f);
        alphaAnim.setDuration(1000);
        alphaAnim.setRepeatMode(ValueAnimator.RESTART);
        alphaAnim.setInterpolator(new LinearInterpolator());
        alphaAnim.setRepeatCount(repeatCount);
        animators.add(alphaAnim);

        AnimatorSet as = new AnimatorSet();
//        as.setInterpolator(new LinearInterpolator());
        as.playTogether(animators);
        //这里 alphaAnim 设置监听，不能用 AnimatorSet 做监听
        if (alphaAnim.getListeners() != null) {
            alphaAnim.getListeners().clear();
        }
        alphaAnim.addListener(new AnimatorListenerAdapter() {
            int count = repeatCount + 1;// 加1为第一次要显示的数字 5

            @Override
            public void onAnimationStart(Animator animation) {// 此方法执行1次
                animView.setVisibility(View.VISIBLE);
                setAnimationStyle();
                count--;
                if (listener != null){
                    listener.onAnimationStart(animation);
                }
            }

            @Override
            public void onAnimationEnd(Animator animation) {// 此方法执行1次
                // 动画结束 隐藏控件
                animView.setVisibility(View.GONE);
                if (listener != null && count == 0){
                    listener.onAnimationEnd(animation);
                }
            }

            @Override
            public void onAnimationRepeat(Animator animation) {// 此方法执行4次（repeatCount值）
                setAnimationStyle();
                count--;
                if (listener != null){
                    listener.onAnimationRepeat(animation);
                }
            }

            private void setAnimationStyle() {
                if (animView instanceof TextView) {
                    ((TextView) animView).setText(String.valueOf(count));//设置显示的数字
                } else if (animView instanceof ImageView) {
                    if (drawableRes != null) {
                        if (count - 1 >= 0) {
                            ((ImageView) animView).setImageResource(drawableRes[count - 1]);
                        }
                    }
                }
            }
        });
        as.start();
    }

    /**
     * 在主线程的定时器
     */
    public static DefaultObserver<Long> timer(int delayMs,int intervalMs,DefaultObserver<Long> observer){
        //定时刷新行布局倒计时
        Observable.interval(delayMs, intervalMs, TimeUnit.MILLISECONDS)
                .subscribeOn(Schedulers.computation())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(observer);
        return observer;
    }

    public static Bitmap readBitmap(Context context,int resId) {
        Bitmap bitmap;
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP){
            Drawable vectorDrawable = ContextCompat.getDrawable(context,resId);
            if (vectorDrawable == null) return null;
            // 取 drawable 的颜色格式
            Bitmap.Config config = vectorDrawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.ARGB_4444;
            bitmap = Bitmap.createBitmap(vectorDrawable.getIntrinsicWidth(),vectorDrawable.getIntrinsicHeight(), config);
            Canvas canvas = new Canvas(bitmap);
            vectorDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
            vectorDrawable.draw(canvas);
        }else {
            bitmap = BitmapFactory.decodeResource(context.getResources(), resId);
        }
        return bitmap;
    }
}